package cn.getech.data.development.utils.shell;

import cn.getech.data.development.service.ExecuteCommandACallable;
import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.exec.Watchdog;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

@Slf4j
public class ShellUtil {

    public static String executeCommandWithAuth(String command, String host, int port, String user, String pwd, ExecuteCommandACallable<String> buffer){
        Session session = null;
        Channel channel = null;
        InputStream in = null;
        InputStream er = null;
        Watchdog watchdog = new Watchdog(60*60000);//1小时超时
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(user, host, port);

            Properties prop = new Properties();
            //File file = new File(SystemUtils.getUserHome() + "/.ssh/id_rsa");
            //String knownHosts = SystemUtils.getUserHome() + "/.ssh/known_hosts".replace('/', File.separatorChar);
            //jsch.setKnownHosts(knownHosts)
            //jsch.addIdentity(file.getPath())
//            prop.put("PreferredAuthentications", "publickey");
            prop.put("PreferredAuthentications", "password");

            prop.put("StrictHostKeyChecking", "no");
            session.setConfig(prop);
            session.setPort(port);
            session.setPassword(pwd);
            session.connect();

            channel = session.openChannel("exec");
            ((ChannelExec) channel).setPty(false);
            ((ChannelExec) channel).setCommand(command);

            // get I/O streams
            in = channel.getInputStream();
            er = ((ChannelExec) channel).getErrStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(er, StandardCharsets.UTF_8));

            Thread thread = Thread.currentThread();
            watchdog.addTimeoutObserver(w -> thread.interrupt());

            channel.connect();
            watchdog.start();
            String buf;
            while ((buf = reader.readLine()) != null) {
                buffer.appendBuffer(buf);
                if (buffer.IamDone()) {
                    break;
                }
            }
            String errbuf;
            while ((errbuf = errorReader.readLine()) != null) {
                buffer.appendBuffer(errbuf);
                if (buffer.IamDone()) {
                    break;
                }
            }

            //两分钟超时，无论什么代码，永久运行下去并不是我们期望的结果，
            //加超时好处多多，至少能防止内存泄漏，也能符合我们的预期，程序结束，相关的命令也结束。
            //如果程序是前台进程，不能break掉，那么可以使用nohup去启动，或者使用子shell，但外层我们的程序一定要能结束。
            watchdog.stop();
            channel.disconnect();
            session.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                if (er != null) {
                    er.close();
                }
            } catch (Exception e) {
                //
            }

            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
            watchdog.stop();
        }

        return buffer.endBuffer();
    }

    /*public static void main(String[] args) {
        try {
            List<String> resultList = new ArrayList<>();
            ExecuteCommandACallable<String> buffer = new ExecuteCommandACallable<String>() {
                @Override
                public boolean IamDone() {
                    return false;
                }

                @Override
                public ExecuteCommandACallable<String> appendBuffer(String content) {
                    resultList.add(content);
                    return null;
                }

                @Override
                public String endBuffer() {
                    return null;
                }
            };
            ///opt/cloudera/parcels/FLINK/lib/flink/bin/flink run -m yarn-cluster /usr/realtime/WindowJoin.jar -c org.apache.flink.streaming.examples.join.WindowJoin -p 1 -yjm 1024 -ytm 2048 -ys 8
            ShellUtil.executeCommandWithAuth("source /etc/profile \n flink run -m yarn-cluster /usr/realtime/WindowJoin.jar -c org.apache.flink.streaming.examples.join.WindowJoin -p 1 -yjm 1024 -ytm 2048 -ys 8 2>&1", "10.74.20.70",
                    22222, "root", "root@123", buffer);
            System.out.println(resultList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }*/

}
